package com.android.common.utils;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.android.common.R;
import com.android.common.constant.DateFormatConstant;
import com.android.common.network.ProgressListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.ResponseBody;

public class FileUtil {

    public static File saveFile(ResponseBody responseBody, String destFileDir
            , String destFileName, ProgressListener listener) throws IOException {
        return saveFileWithCallback(responseBody, destFileDir, destFileName);
    }

    /**
     * 将文件写入本地
     *
     * @param destFileDir  目标文件夹
     * @param destFileName 目标文件名
     * @return 写入完成的文件
     * @throws IOException IO异常
     */
    public static File saveFileWithCallback(ResponseBody responseBody, String destFileDir
            , String destFileName) throws IOException {
        InputStream is = responseBody.byteStream();
        long contentLength = responseBody.contentLength();
        long totalBytesRead = 0L;

        byte[] buf = new byte[2048];
        int len;
        FileOutputStream fos = null;
        try {
            File dir = new File(destFileDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            File file = new File(dir, destFileName);
            if (file.exists()) {
                file.delete();
            }
            fos = new FileOutputStream(file);
            while ((len = is.read(buf)) != -1) {
                fos.write(buf, 0, len);
                totalBytesRead += len != -1 ? len : 0;
            }
            fos.flush();
            return file;

        } finally {
            try {
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (fos != null) fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static Uri saveFileToDownload(Context context, ResponseBody responseBody, String fileName, ProgressListener listener) {
        try {
            InputStream is = responseBody.byteStream();
            BufferedInputStream bis = new BufferedInputStream(is);
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
            Uri uri = context.getContentResolver().insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
            if (uri != null) {
                OutputStream outputStream = context.getContentResolver().openOutputStream(uri);
                if (outputStream != null) {
                    BufferedOutputStream bos = new BufferedOutputStream(outputStream);
                    byte[] buf = new byte[2048];
                    int bytes = bis.read(buf);
                    while (bytes >= 0) {
                        bos.write(buf, 0, bytes);
                        bos.flush();
                        bytes = bis.read(buf);
                    }
                    bos.close();
                    return uri;
                }
            }
            bis.close();
        } catch (FileNotFoundException e) {
            Log.e("download", e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("download", e.getMessage());
            e.printStackTrace();
        }
        return null;

    }

    public static boolean deleteFile(String url) {
        boolean result = false;
        File file = new File(url);
        if (file.exists()) {
            result = file.delete();
        }
        return result;
    }

    public static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }


    /**
     * 建立目录
     *
     * @param dir 目录
     * @return 是否成功创建
     */
    public static boolean makeDirs(String dir) {
        if (dir.startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) {
            //判断sd卡状态
            if (checkSdcard()) {
                File fDir = new File(dir);
                if (!fDir.exists()) {
                    boolean flag = fDir.mkdirs();
                    return flag;
                }
                return true;
            } else {
                return false;
            }
        } else {
            File fDir = new File(dir);
            if (!fDir.exists()) {
                boolean flag = fDir.mkdirs();
                return flag;
            }
            return true;
        }
    }

    public static boolean makeDirs(File dir) {
        return makeDirs(dir.getAbsolutePath());
    }

    public static boolean createNoMedia(String parent) {
        if (!makeDirs(parent)) return false;
        File file = new File(parent, ".nomedia");
        if (file.exists()) {
            if (file.isFile()) {
                return true;
            } else {
                FileUtil.deleteFile(file.getAbsolutePath());
            }
        }
        try {
            return file.createNewFile();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /*
     *check apk 的完整性
     */
    public static boolean checkApk(Context context, String filePath) {
        boolean result = false;
        try {
            PackageManager pm = context.getPackageManager();
            PackageInfo info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
            if (info != null) {
                result = true;//完整
            }
        } catch (Exception ignore) {
        }
        return result;
    }

    /**
     * 通知扫描文件
     *
     * @param context context
     * @param file    file
     */
    public static void scanMediaFile(Context context, File file) {
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
    }

    private static boolean checkSdcard() {
        return TextUtils.equals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
    }

    /**
     * 设置拍照目录
     *
     * @return data/user/0/com.android.main/files/capture
     */
    public static String getCapturePath(Context context) {
        return context.getFilesDir().toString();
    }

    /**
     * 设置拍照目录
     *
     * @return /sdcard/
     */
    public static String getCropPath() {
        return Environment.getExternalStorageDirectory().getPath();
    }

    /**
     * 设置文件名
     *
     * @return
     */
    public static String getFileNameByTime() {
        return DateUtil.formatCurrentTime(DateFormatConstant.DATE_TIME_FORMAT_3);
    }

    /**
     * 返回带日期的名称
     *
     * @param prefix 文件名前缀(会自动拼接 _ )
     * @return String
     */
    public static String getFileNameByTime(String prefix) {
        if (!TextUtils.isEmpty(prefix)) {
            return prefix + "_" + DateUtil.formatCurrentTime(DateFormatConstant.DATE_TIME_FORMAT_3);
        } else {
            return DateUtil.formatCurrentTime(DateFormatConstant.DATE_TIME_FORMAT_3);
        }
    }

    public static void saveBitmap2File(Context context, Bitmap bitmap, String filePath) {
        File file = new File(filePath);
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
            bos.flush();
            bos.close();
            scanFile(context, file);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getRecordScreenPath(Activity mActivity) {
        //安卓系统环境版本在29以下时：
        /*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_DCIM + "/" + FileUtil.getFileNameByTime("Recorder") + ".mp4";
        } else {
            return mActivity.getExternalFilesDir(null).getPath() + File.separator + FileUtil.getFileNameByTime("Recorder") + ".mp4";
        }*/
        return mActivity.getExternalFilesDir(null).getPath() + File.separator + FileUtil.getFileNameByTime("Recorder") + ".mp4";
    }

    public static String getCaptureScreenPath(Activity mActivity) {
//        return context.getExternalFilesDir(null) + "/" + FileUtil.getFileNameByTime("Capture") + ".png";
        return mActivity.getExternalFilesDir(null).getPath() + File.separator + FileUtil.getFileNameByTime("Capture") + ".jpeg";
    }

    public static void saveFile2Gallery(Context context, boolean isVideo, Uri uri, String fileName) {
        String folderName = "";
        if (isVideo) {
            folderName = Environment.DIRECTORY_DCIM + "/" + context.getString(R.string.app_name);
        } else {
            folderName = Environment.DIRECTORY_PICTURES + "/" + context.getString(R.string.app_name);
        }
        Uri uriSavedFile;
        File createdFile = null;
        ContentResolver resolver = context.getContentResolver();
        ContentValues valuesFile;
        valuesFile = new ContentValues();

        if (Build.VERSION.SDK_INT >= 29) {
            valuesFile.put(MediaStore.Video.Media.RELATIVE_PATH, folderName);
            valuesFile.put(MediaStore.Video.Media.TITLE, fileName);
            valuesFile.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
            valuesFile.put(MediaStore.Video.Media.MIME_TYPE, isVideo ? "video/mp4" : "image/jpeg");
            valuesFile.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);

            Uri collection = isVideo ? MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY) :
                    MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
            uriSavedFile = resolver.insert(collection, valuesFile);
        } else {
            File directory = Environment.getExternalStoragePublicDirectory(isVideo ? Environment.DIRECTORY_DCIM : Environment.DIRECTORY_PICTURES);
            File parent = new File(directory.getAbsolutePath() + "/" + context.getString(R.string.app_name));
            if (!parent.exists()) {
                parent.mkdir();
            }
            createdFile = new File(parent, fileName + (isVideo ? ".mp4" : ".jpeg"));
            valuesFile.put(MediaStore.Video.Media.TITLE, fileName);
            valuesFile.put(MediaStore.Video.Media.DISPLAY_NAME, fileName);
            valuesFile.put(MediaStore.Video.Media.MIME_TYPE, isVideo ? "video/mp4" : "image/jpeg");
            valuesFile.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis() / 1000);
            valuesFile.put(MediaStore.Video.Media.DATA, createdFile.getAbsolutePath());
            if (isVideo) {
                uriSavedFile = context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        valuesFile);
            } else {
                uriSavedFile = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        valuesFile);
            }
        }

        if (Build.VERSION.SDK_INT >= 29) {
            valuesFile.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis());
            valuesFile.put(MediaStore.Video.Media.IS_PENDING, 1);
        }

        try {
            if (isVideo) {
                ParcelFileDescriptor pfd;
                pfd = context.getContentResolver().openFileDescriptor(uriSavedFile, "w");

                FileOutputStream out = new FileOutputStream(pfd.getFileDescriptor());
                // get the already saved video as fileinputstream
                // The Directory where your file is saved
                // File storageDir = new File(uri.getPath());
                //Directory and the name of your video file to copy
                File videoFile = new File(uri.getPath());
                FileInputStream in = new FileInputStream(videoFile);
                byte[] buf = new byte[8192];
                int len;
                while ((len = in.read(buf)) > 0) {
                    out.write(buf, 0, len);
                }

                out.close();
                in.close();
                pfd.close();
            } else {
                OutputStream out = context.getContentResolver().openOutputStream(uriSavedFile);
                BitmapFactory.Options options = new BitmapFactory.Options();
                Bitmap bmp = BitmapFactory.decodeStream(resolver.openInputStream(uri));
                bmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
                bmp.recycle();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (Build.VERSION.SDK_INT >= 29) {
            valuesFile.clear();
            valuesFile.put(MediaStore.Video.Media.IS_PENDING, 0);
            context.getContentResolver().update(uriSavedFile, valuesFile, null, null);
        } else {
            Intent localIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
            final Uri localUri = Uri.fromFile(createdFile);
            localIntent.setData(localUri);
            context.sendBroadcast(localIntent);
        }
    }

    /**
     * 主动扫描文件，入库
     *
     * @param context
     * @param path
     */
    public static void scanFile(Context context, String path) {
        try {
            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri uri = Uri.fromFile(new File(path));
            intent.setData(uri);
            context.sendBroadcast(intent);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     * 主动扫描文件，入库
     *
     * @param context
     * @param file
     */
    public static void scanFile(Context context, File file) {
        try {
            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            Uri uri = Uri.fromFile(file);
            intent.setData(uri);
            context.sendBroadcast(intent);
        } catch (Exception exception) {
            exception.printStackTrace();
        }
    }

    /**
     * AndroidQ以上保存图片到公共目录
     *
     * @param imageName    图片名称
     * @param imageType    图片类型
     * @param relativePath 缓存路径
     */
    public static Uri insertImageFileIntoMediaStore(Context context, String imageName, String imageType,
                                                    String relativePath) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return null;
        }
        if (TextUtils.isEmpty(relativePath)) {
            return null;
        }
        Uri insertUri = null;
        ContentResolver resolver = context.getContentResolver();
        //设置文件参数到ContentValues中
        ContentValues values = new ContentValues();
        //设置文件名
        values.put(MediaStore.Images.Media.DISPLAY_NAME, imageName);
        //设置文件描述，这里以文件名代替
        values.put(MediaStore.Images.Media.DESCRIPTION, imageName);
        //设置文件类型为image/*
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imageType);
        //注意：MediaStore.Images.Media.RELATIVE_PATH需要targetSdkVersion=29,
        //故该方法只可在Android10的手机上执行
        values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath);
        //EXTERNAL_CONTENT_URI代表外部存储器
        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        //insertUri表示文件保存的uri路径
        insertUri = resolver.insert(external, values);
        return insertUri;
    }

    /**
     * 将输入流写入到输出流程中
     */
    public static void writeIns2Outs(InputStream in, OutputStream outs) throws IOException {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = in.read(buffer))>0){
            outs.write(buffer, 0, length);
        }
        outs.flush();
        outs.close();
        in.close();
    }

    // 修复 android.webkit.MimeTypeMap 的 getFileExtensionFromUrl 方法不支持中文的问题
    public static String getFileExtensionFromUrl(String url) {
        if (!TextUtils.isEmpty(url)) {
            int fragment = url.lastIndexOf('#');
            if (fragment > 0) {
                url = url.substring(0, fragment);
            }

            int query = url.lastIndexOf('?');
            if (query > 0) {
                url = url.substring(0, query);
            }

            int filenamePos = url.lastIndexOf('/');
            String filename =
                    0 <= filenamePos ? url.substring(filenamePos + 1) : url;

            // if the filename contains special characters, we don't
            // consider it valid for our matching purposes:
            // 去掉正则表达式判断以添加中文支持
//          if (!filename.isEmpty() && Pattern.matches("[a-zA-Z_0-9\\.\\-\\(\\)\\%]+", filename))
            if (!filename.isEmpty()) {
                int dotPos = filename.lastIndexOf('.');
                if (0 <= dotPos) {
                    // 后缀转为小写
                    return filename.substring(dotPos + 1).toLowerCase();
                }
            }
        }

        return "";
    }

}
